/* Copyright (C) 2008, 2009, 2010 Faindu GmbH, Switzerland.
* All Rights Reserved. The following is Source Code and is subject to all restrictions 
* on such code as contained in the license accompanying this project. */
package blocstac.editimage.base
{
import org.mockito.MockitoTestCase;

public class UndoManagerTest extends MockitoTestCase
{
	function UndoManagerTest() {
		super([ImageOperation])
	}
	
    //==========================================================================
    //
    //  Test set up and tear down
    //
    //--------------------------------------------------------------------------  
	private var undoManager:UndoManager
	private var stateManager:StateManager
	private var op:ImageOperation
	private var state1:ImageModel
	private var state2:ImageModel
	
	override public function setUp(): void
	{
		undoManager = new UndoManager(canUndoRedoChanged)
		op = mock(ImageOperation)
		
		state1 = new ImageModel()
		state1.angle = 1
		state2 = new ImageModel()
		state2.angle = 2
	}
	
	override public function tearDown():void
	{
	}
	
	private var _canUndoRedoChangedHasBeendCalled:Boolean
	private function canUndoRedoChanged():void {
		_canUndoRedoChangedHasBeendCalled = true
	}
	
    //==========================================================================
    //
    //  Tests
    //
    //--------------------------------------------------------------------------  
	[Test]
	public function test_initial_undo(): void
	{
		assertFalse(undoManager.undo(state2))
	}

	[Test]
	public function test_addOperation(): void {
		assertFalse(_canUndoRedoChangedHasBeendCalled)
		undoManager.addOperation(op)
		assertTrue(_canUndoRedoChangedHasBeendCalled)
		
		_canUndoRedoChangedHasBeendCalled = false
		undoManager.addOperation(op)
		assertFalse(_canUndoRedoChangedHasBeendCalled)
	}
	
	[Test]
	public function test_undo(): void
	{
		undoManager.addOperation(op)
		assertTrue(undoManager.undo(state1))
		
		verify().that(op.undo(state1))
		assertFalse(undoManager.canUndo())
		assertTrue(undoManager.canRedo())
	}

	[Test]
	public function test_undo_last_operation(): void {
		undoManager.addOperation(op)
		_canUndoRedoChangedHasBeendCalled = false
		assertTrue(undoManager.undo(state1))
		assertTrue(_canUndoRedoChangedHasBeendCalled)
	}

	[Test]
	public function test_undo_second_last_operation(): void {
		undoManager.addOperation(op)
		undoManager.addOperation(op)
		_canUndoRedoChangedHasBeendCalled = false
		assertTrue(undoManager.undo(state1))
		assertTrue(_canUndoRedoChangedHasBeendCalled) // canRedo changed
	}

	[Test]
	public function test_second_undo(): void {
		undoManager.addOperation(op)
		undoManager.addOperation(op)
		undoManager.addOperation(op)
		assertTrue(undoManager.undo(state1))
		_canUndoRedoChangedHasBeendCalled = false
		assertTrue(undoManager.undo(state1))
		assertFalse(_canUndoRedoChangedHasBeendCalled)
	}

	[Test]
	public function test_redo(): void
	{
		undoManager.addOperation(op)
		undoManager.undo(state1)
		assertTrue(undoManager.redo(state2))
		
		verify().that(op.apply(state2))
		assertTrue(undoManager.canUndo())
		assertFalse(undoManager.canRedo())
	}

	[Test]
	public function test_redo_canUndoRedoChanged(): void {
		undoManager.addOperation(op)
		undoManager.undo(state1)
		_canUndoRedoChangedHasBeendCalled = false
		assertTrue(undoManager.redo(state2))
		assertTrue(_canUndoRedoChangedHasBeendCalled)
	}

	[Test]
	public function test_max_10_undos(): void
	{
		const MAX_UNDOS:int = 10
		var ops:Vector.<ImageOperation> = new Vector.<ImageOperation>()
		for (var i:int=1; i<=MAX_UNDOS+2; ++i) {
			var newOp:ImageOperation = mock(ImageOperation)
			ops.push(newOp)
			undoManager.addOperation(newOp)
		}
		undoManager.undo(state1)
		verify().that(ops[MAX_UNDOS+1].undo(state1))
		
		for (var ii:int=1; ii<=MAX_UNDOS-2; ++ii) {
			assertTrue(undoManager.undo(state1))
		}
		assertTrue(undoManager.undo(state2))
		verify().that(ops[2].undo(state2))
		
		assertFalse(undoManager.canUndo())
	}
	
	[Test]
	public function test_canUndo(): void
	{
		assertFalse(undoManager.canUndo())
		undoManager.addOperation(op)
		assertTrue(undoManager.canUndo())
	}
	
	[Test]
	public function test_canRedo(): void
	{
		assertFalse(undoManager.canRedo())
		undoManager.addOperation(op)
		assertFalse(undoManager.canRedo())
		undoManager.undo(state1)
		assertTrue(undoManager.canRedo())
	}
	
	[Test]
	public function test_reset(): void
	{
		undoManager.addOperation(op)
		undoManager.addOperation(op)
		undoManager.undo(state1)
		
		assertTrue(undoManager.canUndo())
		assertTrue(undoManager.canRedo())
		
		undoManager.reset()
		assertFalse(undoManager.canUndo())
		assertFalse(undoManager.canRedo())
	}
	
	[Test]
	public function test_reset_calls_canUndoRedoChanged(): void
	{
		undoManager.addOperation(op)
		undoManager.addOperation(op)
		undoManager.undo(state1)
		_canUndoRedoChangedHasBeendCalled = false

		undoManager.reset()
		assertTrue(_canUndoRedoChangedHasBeendCalled)
	}
	
}
}